package customer

import (
	"context"
	"fmt"
	"sieve_admin_server_userpass/app/dao/user"
	"sieve_admin_server_userpass/lib/log"
	"sieve_admin_server_userpass/lib/util/errors"
	pkgCron "sieve_admin_server_userpass/pkg/cron"
	"strings"
	"sync"
	"time"
)

var (
	uerAuthCron          *pkgCron.Cron
	initUserAuthFinished bool
)

func (a *UserAuthSrv) init() error {

	var (
		initCount = 2
		wp        = sync.WaitGroup{}
		logMsg    []string
	)

	wp.Add(initCount)
	go func() {
		err := a.loadSessions()
		logMsg = append(logMsg, fmt.Sprintf("%+v", err))
		wp.Done()
	}()

	go func() {
		err := a.initAccount()
		logMsg = append(logMsg, fmt.Sprintf("%+v", err))
		wp.Done()
	}()
	wp.Wait()

	initUserAuthFinished = true
	return errors.New(strings.Join(logMsg, ","))
}

func (a *UserAuthSrv) WaitFinished() {

	for !initUserAuthFinished {
		time.Sleep(time.Millisecond * 10)
	}
}

func (a *UserAuthSrv) Cron() error {

	uerAuthCron = pkgCron.New(pkgCron.WithLocation(time.Local))
	log.Info(fmt.Sprintf("%v", a.init()))

	var (
		scheduleJobList = []struct {
			Spec    string
			Comment string
			pkgCron.FuncJob
		}{
			{
				// 同步搜索表
				// Spec: "30 0 * * *",
				Spec: "@every 1s",
				// Spec:    "@every 10s",
				// Comment: "每天凌晨0点30分执行",
				Comment: "每秒执行一次",
				FuncJob: a.delExpireSession,
			},
		}
	)

	for _, v := range scheduleJobList {
		_, _ = uerAuthCron.AddFunc(v.Spec, v.FuncJob)
	}

	uerAuthCron.Run()

	return nil
}

func (a *UserAuthSrv) initAccount(args ...interface{}) error {

	var (
		now    = time.Now()
		entity = user.User{}
		item   = map[string]interface{}{
			"account":    adminAccount.Account,
			"passwd":     adminAccount.Passwd,
			"create_at":  now.Unix(),
			"updated_at": now.Unix(),
		}
		checkDupSQL = fmt.Sprintf(`
		SELECT
			* 
		FROM
		    user
		WHERE
		    account = '%v' AND deleted = 0 AND status = 1
`, adminAccount.Account)
	)

	req, err := a.UserRepo.QueryRaw(context.Background(), checkDupSQL, entity)
	if err != nil {
		log.Err("query admin account err:%+v", err)
		return err
	}

	if req == nil {

		if id, err := a.RoleSrv.CreateRole(context.Background(), 1); err != nil {
			log.Err("初始化管理员角色失败：%+v", err)
		} else {
			item["role_id"] = uint64(id)
			item["id"] = adminAccount.ID
			item["leader_id"] = adminAccount.ID
			item["top_leader_id"] = item["leader_id"]
			item["creator"] = item["leader_id"]
			UpdateAdminAccount(uint64(id))
		}

		if rowsAffected, err := a.UserRepo.Create(context.Background(), item); err != nil {
			log.Err("create admin account err:%+v", err)
			return err
		} else {
			id, _ := rowsAffected.LastInsertId()
			adminAccount.ID = uint64(id)
		}
	} else {
		respUser := req[0].(*user.User)
		adminAccount.ID = respUser.ID
		a.RoleSrv.UpdateAdminRoleId(respUser.RoleId)
		UpdateAdminAccount(respUser.RoleId)

		if _, err := a.RoleSrv.CreateRole(context.Background(), 1); err != nil {
			log.Err("初始化管理员角色失败：%+v", err)
		}
	}

	if _, err := a.RoleSrv.CreateRole(context.Background(), 2); err != nil {
		log.Err("初始化业务员商角色失败：%+v", err)
	}

	if _, err := a.RoleSrv.CreateRole(context.Background(), 3); err != nil {
		log.Err("初始化代理商角色失败：%+v", err)
	}

	if _, err := a.RoleSrv.CreateRole(context.Background(), 4); err != nil {
		log.Err("初始化渠道主角色失败：%+v", err)
	}

	return nil
}

func (a *UserAuthSrv) loadSessions(args ...interface{}) error {

	var (
		tableName = user.UserAuth{}.TableName()
		querySQL  = fmt.Sprintf(`SELECT * FROM %v`, tableName)
	)

	resp, err := a.UserAuthRepo.QueryRaw(context.Background(), querySQL, user.UserAuth{})
	if err != nil {
		log.Err(fmt.Sprintf("load session err %+v", err))
		return err
	}

	for _, v := range resp {
		ua := v.(*user.UserAuth)
		sessions[ua.Uid] = ua
	}

	return nil
}

func (a *UserAuthSrv) delExpireSession(args ...interface{}) {

	sessLock.Lock()
	defer sessLock.Unlock()
	now := time.Now().Unix()
	var (
		tableName = user.UserAuth{}.TableName()
		del       []*user.UserAuth
	)
	if len(args) > 0 {
		if _, ok := sessions[args[0].(uint64)]; ok {
			del = append(del, &user.UserAuth{
				Uid: args[0].(uint64),
			})
		}
	} else {

		for _, sess := range sessions {
			if now > sess.ExpireTime {
				del = append(del, sess)
			}
		}
	}
	for _, sess := range del {
		delete(sessions, sess.Uid)

		delSQL := fmt.Sprintf("DELETE FROM `%v` WHERE `uid`=%v", tableName, sess.Uid)
		_, _ = a.UserAuthRepo.ExecRaw(context.Background(), delSQL)
	}
}
